
/* Generated by Interface Builder */

#import "Help.h"
#import "Dispatcher.h"
#import <appkit/Button.h>
#import <appkit/Cell.h>
#import <appkit/Matrix.h>
#import <appkit/MenuCell.h>
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <dpsclient/wraps.h>
#import <sys/dir.h> //for getdirentries()
#import <libc.h>     
#import <strings.h>

@implementation Help

- init
{
	if (!strlen([NXApp appDirectory]))
		[NXApp init];
	sprintf(helpDir, "%s/%s", [NXApp appDirectory], "Help");
	printf("helpDir = %s\n", helpDir);
	sprintf(noHelpFile, "%s/%s", helpDir, "No Help.rtf");
	helpPanel = [NXApp loadNibSection:"help.nib" owner:self];
	return self;
}

- setHelpBrowser:anObject
{
	helpBrowser = anObject;
	[helpBrowser setDelegate:self];
	[helpBrowser loadColumnZero];
	return self;
}

- generalHelp:sender
{
	[self showHelpFile:"Overview"];
	return self;
}

- browserHit:sender
{
	[self showHelpFile:[[[sender matrixInColumn:0] selectedCell] stringValue]];
	return self;
}

- print:sender
{
	[[helpScroll docView] printPSCode:sender];
	return self;
}

- showHelpFile:(const char *)filename
{
   NXStream *stream;
   char helpFile[MAXPATHLEN];
   static NXPoint origin = {0.0,0.0};
   

if (![self browser:helpBrowser selectCell:filename inColumn:0])
        [self browser:helpBrowser selectCell:"No Help" inColumn:0]; 
    sprintf(helpFile,"%s/%s.rtf",helpDir,filename); 
    if ((stream = NXMapFile(helpFile,NX_READONLY)) == NULL)
        stream = NXMapFile(noHelpFile,NX_READONLY);
    if (stream != NULL) {
    	[helpPanel disableFlushWindow];
        [[helpScroll docView] readRichText:stream]; 
	[[helpScroll docView] scrollPoint:&origin];
	[[helpPanel reenableFlushWindow] flushWindow];
    	NXCloseMemory(stream,NX_FREEBUFFER);
    }
    [helpPanel orderFront:self];
    return self;
}

#define CHUNK	127
static char **addFile(const char *file, int length, char **list, int count)
{
	char	*suffix;
	
	if (!list) list = (char**)malloc(CHUNK*sizeof(char *));
	if (suffix = rindex(file,'.'))
		*suffix = '\0';
	list[count] = (char *)malloc((length + 1)*sizeof(char));
	strcpy(list[count], file);
	count++;
	if (!(count % CHUNK)) {
		list = (char **)realloc(list, (((count/CHUNK)+1)*CHUNK)*sizeof(char *));
	}
	list[count] = NULL;
	return list;
}

static void freeList(char **list)
{
	char	**strings;
	
	if (list) {
		strings = list;
		while (*strings)
			free(*strings++);
		free(list);
	}
}

static BOOL isOk(const char *s)
/* checks to make sure the filename is not NULL and to verify that it is
 * not a "dot"--hidden file.
 */
{
    return (!s[0] || s[0] == '.') ? NO : YES;
}

static int caseInsensitiveCompare(void *arg1, void *arg2)
/* Compares the two arguments without regard for case using strcasecmp().
*/
{
    char *string1, *string2;

    string1 = *((char **)arg1);
    string2 = *((char **)arg2);
    return strcasecmp(string1,string2);
}

static char **fileList;

- (int)browser:sender fillMatrix:matrix inColumn:(int)column
/* This delegate method goes out to the help directory and gets a list
 * of all the files in that directory.  It creates a list of file names
 * for the static variable fileList, and will load the filenames into the 
 * browser on demand (lazy loading).
 */
{
    long basep;
    char *buf;
    struct direct *dp;
    char **list = NULL;
    int cc, fd, fileCount = 0;
    char dirbuf[8192];

    if ((fd = open(helpDir, O_RDONLY, 0644)) > 0) {
	cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
	while (cc) {
	    dp = (struct direct *)buf;
	    if (isOk(dp->d_name)) {
		list = addFile(dp->d_name, dp->d_namlen, list, fileCount++);
	    }
	    buf += dp->d_reclen;
	    if (buf >= dirbuf + cc) {
		cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
	    }
	}
	close(fd);
	if (list) qsort(list,fileCount,sizeof(char *),caseInsensitiveCompare);
    }
    freeList(fileList);
    fileList = list;
    return fileCount;
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
/* This delegate method loads the cell for a given row.  The stringValue
 * for that row comes from the fileList.
 */
{
    if (fileList) {
	[cell setStringValueNoCopy:fileList[row]];
	[cell setLeaf:YES];
    }
    return self;
}


- (BOOL)browser:sender selectCell:(const char *)title inColumn:(int)column
/* This delegate method selects the cell with the given title.  If it finds
 * a cell with that title, it verifies that it has a file entry in the 
 * fileList, forces the loading of the cell, selects it (highlights) and
 * scrolls the browser so the cell is visible.  It returns a boolean value
 * which indicates whether the cell was found.
 */
{
    int row;
    id matrix;

    if (title) {
	matrix = [sender matrixInColumn:column];
	if (!fileList) return NO;
	for (row = [matrix cellCount]-1; row >= 0; row--) {
	    if (fileList[row] && !strcmp(title, fileList[row])) {
		[sender getLoadedCellAtRow:row inColumn:column];
		[matrix selectCellAt:row :0];
		[matrix scrollCellToVisible:row :0];
		return YES;
	    }
	}
    }
    return NO;
}


/* WINDOW DELEGATE METHODS */

- windowWillResize:sender toSize:(NXSize *)frameSize;
/* This method constrains the Help Panel to a reasonable minimum size
 * when the user resizes the panel.
 */
{
    frameSize->width = MAX(frameSize->width,400.0);
    frameSize->height = MAX(frameSize->height,350.0);
    return self;
}


@end
